package pack1

import (
	"fmt"
	"reflect"
)

type Connector interface {
	connect() bool
}

type MySql struct {
	name string
}

type Closer interface {
	close() bool
}

func (ms *MySql) connect() bool {
	fmt.Printf("%s connect...\n", ms.name)
	return true
}

func (ms *MySql) close() bool {
	fmt.Printf("%s close\n", ms.name)
	return true
}

type MsSql struct {
	name string
}

func (ms *MsSql) connect() bool {
	fmt.Printf("%s connect...\n", ms.name)
	return true
}

func connect(connector Connector) {
	connector.connect()
}

type MyCar struct {
	name string
}

type MyCars []*MyCar

func (cars MyCars) Process(f func(c *MyCar)) {
	for _,c := range cars {
		f(c)
	}
}

func (cars MyCars) findAll(f func(c *MyCar) bool) MyCars {
	fCars := make([]*MyCar, 0)
	cars.Process(func(c *MyCar) {
		if f(c) {
			fCars = append(fCars, c)
		}
	})
	return fCars
}

func TestInterface3()  {
	mycars := MyCars{
		&MyCar{"car1"},
		&MyCar{"car2"},
	}
	//fmt.Println("mycars", mycars)

	fCars := mycars.findAll(func(c *MyCar) bool {
		return c.name == "car1"
	})

	for _,cPtr := range fCars {
		fmt.Println("car:", *cPtr)
	}
}

func TestInterface2() {
	mysql := new(MySql)
	mysql.name = "mysql"
	//connect(mysql)

	mssql := new(MsSql)
	mssql.name = "mssql"

	var connector Connector
	connector = mysql
	connector.connect()

	if x,v := connector.(Closer); v {
		x.close()
	}

	t1 := reflect.TypeOf(connector)
	fmt.Printf("%v \n", t1)

	var x float64 = 3.4
	fmt.Println("type:", reflect.TypeOf(x))

	v := reflect.ValueOf(x)
	fmt.Println("value type", v.Type(), v.Kind(), v.Interface().(float64))


	type Dog struct {
		LegCount int    //注意字段的首字母是小写
	}
	//获取Dog实例地址的反射值对象
	dog := new(Dog)
	dog.LegCount = 10
	valueOfDog := reflect.ValueOf(dog)
	fmt.Printf("valueOfDog type: %T\n", valueOfDog)

	doeElm := valueOfDog.Elem()

	//获取legCount字段的反射值对象
	vLegCount := doeElm.FieldByName("LegCount")

	//尝试设置legCount字段值（这里会发生崩溃）
	vLegCount.SetInt(4)

	fmt.Println("legCount =", vLegCount.Int())

	fmt.Println("dog", dog)

	//fmt.Println("mysql change value:", mysqlValue.Interface().(*MySql))
	//t1.

}



func TestInterface() {
	mysql := new(MySql)
	mysql.name = "mysql"
	//connect(mysql)

	mssql := new(MsSql)
	mssql.name = "mssql"
	//connect(mssql)

	var v Connector
	v = mysql
	s, ok := v.(*MsSql)
	if ok {
		s.connect()
		//fmt.Println(s.connect())
	}

	switch t := v.(type) {
	case *MySql:
		fmt.Println("mysql connector", t)
	}

	//conn := Connector(mysql)
	//conn.connect()

	classifier(true, "raw string", false)


	var any interface{}
	any =mysql

	fmt.Printf("any = %v\n", any)

	vector := new(Vector)
	vector.append(true)
	vector.append("raw string")
	vector.append(3.14)
	vector.append(5)
	fmt.Printf("vector length = %d\n", vector.len())
	fmt.Printf("index at %d = %v\n", 1, vector.At(1))
	vector.Set(0, false)

	for i,v := range vector.a {
		fmt.Printf("index: %d, value = %v\n", i, v)
	}
}


type Element interface {}

type Vector struct {
	a []Element
}

func (v *Vector) append(any interface{}) {
	v.a = append(v.a, any)
}

func (v Vector) len() int {
	return len(v.a)
}

func (v *Vector) At(i int) Element {
	return v.a[i]
}

func (v *Vector) Set(i int, element Element) {
	v.a[i] = element
}

func classifier(items ...interface{}) {
	for v, x := range items {
		switch x.(type) {
		case bool:
			fmt.Printf("bool value index = [%d]: %v\n", v, x)
		case string:
			fmt.Printf("string value index = [%d]: %v\n", v, x)
		}
	}
}
